#pragma once
#include <carbon/defs.h>
#include <pthread.h>

CARBON_NS_BEGIN

/// @brief 同步屏障，支持多个线程同步等待
class CARBON_API Barrier final {
    CARBON_NONCOPYABLE(Barrier)
public:
    Barrier() {}
    Barrier(int parties) : Barrier(parties, nullptr) {}
    Barrier(int parties, RunnableFn barrierAction) {
        int ret = pthread_barrier_init(&m_barrier, nullptr, parties);
        assert(ret == 0);
        m_run = std::move(barrierAction);
        this->m_initialized = true;
    }

    Barrier(Barrier && other) 
    : m_barrier(other.m_barrier), m_initialized(other.m_initialized), m_run(std::move(other.m_run)) 
    {
        other.m_initialized = false;
        other.m_run = nullptr;
    }

    ~Barrier() {
        m_run = nullptr;
        if ( this->m_initialized ) {
            pthread_barrier_destroy(&m_barrier);
            this->m_initialized = false;
        }
    }

    Barrier & operator=(Barrier &&other) {
        if ( this == &other) return *this;
        if ( this->m_initialized ) pthread_barrier_destroy(&m_barrier);

        this->m_initialized = other.m_initialized;
        this->m_barrier = other.m_barrier;
        this->m_run = std::move(other.m_run);

        other.m_initialized = false;
        other.m_run = nullptr;
        return *this;
    }

    void await() {
        assert(m_initialized);
        int ret = pthread_barrier_wait(&m_barrier);
        if ( ret == PTHREAD_BARRIER_SERIAL_THREAD || ret == 0 ) {
            if ( m_run )  m_run();
        }
        else assert(ret == 0);
    }

private:
    pthread_barrier_t   m_barrier;
    bool                m_initialized{false};  // 是否已经初始化，用于配合move操作语义, pthread_barrier_t类型无move语义，m_initialized作为资源所有权标记。
    RunnableFn          m_run;
}; // Barrier


CARBON_NS_END

